﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Jermaine.Task
{
    public class TaskFactory
    {
        #region 事件
        public event EventHandler<TaskItemEventArgs> Executing;
        public event EventHandler<TaskItemEventArgs> Completed;
        #endregion


        private Queue<Object> queue = new Queue<Object>();
        private List<Thread> list = new List<Thread>();

        private object mutex = new object();
        private bool isStart = true;
        private bool canEnqueue = true;

        private TaskFactory(int number) {
            Initialize(number);
        }


        protected void OnExecuting(TaskItemEventArgs e) {
            if (Executing != null) {
                Executing(this, e);
            }
        }

        protected void OnCompleted(TaskItemEventArgs e) {
            if (Completed != null) {
                Completed(this, e);
            }
        }

        private void Initialize(int number) {

            for (int i = 0; i < number; i++) {
                var t = new Thread(() => {
                    DoTask();
                });
                t.Name = string.Format("Worker-{0}", i);
                list.Add(t);
            }
        }

        private void DoTask() {
            while (IsStart) {
                object o = null;
                lock (queue) {
                    if (queue.Count > 0) {
                        o = queue.Dequeue();
                    } else if (queue.Count == 0) {
                        Monitor.Wait(queue);
                    }
                }
                if (o != null) {

                    var args = new TaskItemEventArgs {
                        Item = o,
                        ExecutorName = Thread.CurrentThread.Name
                    };

                    OnExecuting(args);

                    if (o is ITask) {
                        (o as ITask).Execute();
                    } else if (o is Delegate) {
                        (o as Delegate).DynamicInvoke();
                    } else {
                        throw new ArgumentException("o");
                    }

                    OnCompleted(args);
                }
            }
        }

        public static TaskFactory Create(int number = 10) {
            return new TaskFactory(number);
        }

        public void Start() {
            IsStart = true;
            foreach (var item in list) {
                item.Start();
            }
        }

        public void Terminate() {
            IsStart = false;
            this.CanEnqueue = false;

            for (int i = 0; i < list.Count; i++) {
                if (list[i].IsAlive) {
                    lock (queue) {
                        Monitor.PulseAll(queue);
                    }
                    list[i].Join();
                }
            }
        }

        public void ForceTerminate() {
            IsStart = false;
            this.CanEnqueue = false;
            for (int i = 0; i < list.Count; i++) {
                list[i].Abort();
                list[i] = null;
            }
        }

        /// <summary>
        /// 加入任务
        /// </summary>
        /// <param name="o"></param>
        public void Put(ITask o) {
            if (!CanEnqueue) {
                return;
            }

            lock (queue) {
                queue.Enqueue(o);
                Monitor.PulseAll(queue);
            }
        }

        /// <summary>
        /// 加入任务
        /// </summary>
        /// <param name="o"></param>
        public void Put(Delegate o) {
            if (!CanEnqueue) {
                return;
            }

            lock (queue) {
                queue.Enqueue(o);
                Monitor.PulseAll(queue);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsStart {
            get {
                lock (mutex) {
                    return isStart;
                }
            }
            set {
                lock (mutex) {
                    isStart = value;
                }
            }
        }

        public bool CanEnqueue {
            get {
                lock (mutex) {
                    return canEnqueue;
                }
            }
            set {
                lock (mutex) {
                    this.canEnqueue = value;
                }
            }
        }
    }



    public class TaskItemEventArgs : System.EventArgs
    {
        public object Item { get; set; }
        public string ExecutorName { get; set; }
    }
}
